/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package modules.legislation.gridcoverage;

import javax.naming.directory.InvalidAttributesException;

import modules.dimensioning.solution.Solution;
import modules.legislation.datatypes.AntennaAndDistance;
import modules.legislation.datatypes.AntennaGroup;
import modules.pathloss.CoverageAdapter;
import tools.math.MathTools;
import datatypes.Antenna;
import datatypes.RadiationPoint;

/**
 *
 * @author Pieter Backaert
 */
public class SamplingGrid implements SamplingGridInterface{

    private int SAMPLING_RESOLUTION;

    private Solution solution;
    private Antenna[] antennas;

    private RadiationPoint[][] radiationPointGrid;
    private AntennaGroup[][] antennaGroupGrid;
    

    private double  minX=999999999,
                    maxX=-999999999,
                    minY=999999999,
                    maxY=-999999999;
    private double step_valueX,
                   step_valueY;



    //hebben we nodig voor later op te vragen : we gaan enkel de mogelijks veranderde
    // SAR-cellen opvragen.
    private int yMinIndex,
                yMaxIndex,
                xMinIndex,
                xMaxIndex;

    private CoverageAdapter ca;

    public SamplingGrid(Solution solution , int SAMPLING_RESOLUTION , CoverageAdapter ca) {
        this.solution = solution;
        this.antennas = this.solution.getAntennas();
        this.SAMPLING_RESOLUTION = SAMPLING_RESOLUTION;
        this.ca = ca;
    }

    public SamplingGrid(Antenna[] antennas , int SAMPLING_RESOLUTION , CoverageAdapter ca) {
        this.antennas = antennas;
        this.SAMPLING_RESOLUTION = SAMPLING_RESOLUTION;
        this.ca = ca;
    }

    public int getXMaxIndex() {
        return xMaxIndex;
    }

    public int getXMinIndex() {
        return xMinIndex;
    }

    public int getYMaxIndex() {
        return yMaxIndex;
    }

    public int getYMinIndex() {
        return yMinIndex;
    }



    public int getSAMPLING_RESOLUTION() {
        return SAMPLING_RESOLUTION;
    }

    public RadiationPoint[][] getRadiationPointGrid() {
        return radiationPointGrid;
    }

    public AntennaGroup[][] getAntennaGroupGrid() {
        return antennaGroupGrid;
    }

    public void initSamplingGrid(){
        for(int i=0 ; i<antennas.length ; i++){
            Antenna a = antennas[i];
            if(a.getX()<minX)
                minX = a.getX();
            if(a.getX()>maxX)
                maxX = a.getX();
            if(a.getY()<minY)
                minY = a.getY();
            if(a.getY()>maxY)
                maxY = a.getY();
        }
        step_valueX = (maxX - minX)/SAMPLING_RESOLUTION;
        step_valueY = (maxY - minY)/SAMPLING_RESOLUTION;


        radiationPointGrid = new RadiationPoint[SAMPLING_RESOLUTION][SAMPLING_RESOLUTION];
        for(int i=0 ; i<SAMPLING_RESOLUTION ; i++){
            for(int j=0 ; j<SAMPLING_RESOLUTION ; j++){
                RadiationPoint rp = new RadiationPoint();
                rp.setXCo(minX+ j*step_valueX);
                rp.setYCo(minY+ i*step_valueY); 
                rp.setSAR(0);
                radiationPointGrid[(SAMPLING_RESOLUTION-1)-i][j] = rp;
            }
        }
        antennaGroupGrid = new AntennaGroup[SAMPLING_RESOLUTION][SAMPLING_RESOLUTION];
        
        int index_limit=1;
        //nu komt de "advanced" stap
        for(int i=0 ; i<antennas.length ; i++){
            //System.out.println("we zitten nu aan : " + index_limit + "/" + antennas.length);
            index_limit++;
            Antenna a = antennas[i];
            try {

                Double d1 = new Double( Math.floor( (a.getX() - minX)/step_valueX)); //floor is ok, want index begint van 0: dus index 2.1 is op 0,1,2
                int index_x = d1.intValue();

                Double d2 = new Double( Math.floor( (a.getY() - minY)/step_valueY));
                int index_y = d2.intValue();

                Double range1 = new Double( Math.ceil( ca.getRangeRadius(a) /step_valueX)); //ceil want vanaf we een cel nog maar binnenkomen moeten we ze meetellen
                int range_x = range1.intValue();

                Double range2 = new Double( Math.ceil( ca.getRangeRadius(a) /step_valueY));
                int range_y = range2.intValue();



                xMinIndex =  index_x-range_x;
                if(xMinIndex<0)
                    xMinIndex=0;
                xMaxIndex =  index_x+range_x;
                if(xMaxIndex> antennaGroupGrid[0].length-1 )
                    xMaxIndex = antennaGroupGrid[0].length-1;
                yMinIndex =  index_y-range_y;
                if(yMinIndex<0)
                    yMinIndex = 0;
                yMaxIndex =  index_y+range_y;
                if(yMaxIndex> antennaGroupGrid.length-1)
                    yMaxIndex = antennaGroupGrid.length-1;

                for(int y=yMinIndex ; y<=yMaxIndex ; y++){
                    for(int x=xMinIndex ; x<=xMaxIndex ; x++){
                        // De XY-assenstelsel indexen terug mappen op de matrix-index !!
                        antennaGroupGrid[ antennaGroupGrid.length-1 -y][x] = updateOrAddToThisAntennaGroup(antennaGroupGrid[ antennaGroupGrid.length-1 -y][x],
                                                                                                                         a , y ,x, true); //a blijft ALTIJD hetzelfde
                        // x en y gaan we nodig hebben omdat we de index moeten weten van sampledGridWithAntennas.
                    }
                } //for
            }
            catch(InvalidAttributesException e){}
        } //for



    } //method



    private void initSamplingGridLEGACY(){
        
        //1. calculate borders

        for(int i=0 ; i<antennas.length ; i++){
            Antenna a = antennas[i];
            if(a.getX()<minX)
                minX = a.getX();
            if(a.getX()>maxX)
                maxX = a.getX();
            if(a.getY()<minY)
                minY = a.getY();
            if(a.getY()>maxY)
                maxY = a.getY();
        }

        // 2. init sampling grid
        step_valueX = (maxX - minX)/SAMPLING_RESOLUTION;
        step_valueY = (maxY - minY)/SAMPLING_RESOLUTION;
        //System.out.println("step value = ok");

        radiationPointGrid = new RadiationPoint[SAMPLING_RESOLUTION][SAMPLING_RESOLUTION];
        for(int i=0 ; i<SAMPLING_RESOLUTION ; i++){
            for(int j=0 ; j<SAMPLING_RESOLUTION ; j++){
                RadiationPoint rp = new RadiationPoint();
                rp.setXCo(minX+ j*step_valueX);
                rp.setYCo(minY+ i*step_valueY); //dit mag omdat
                rp.setSAR(0);
                radiationPointGrid[(SAMPLING_RESOLUTION-1)-i][j] = rp;
            }
        }



        // 3. For each sample value on the grid.
        // calculate distance between each antenna and this sample point.
        // - if antenna is out of reach, do nothing
        // - if antenna is within reach , add to AntennaGangbang[][]
        antennaGroupGrid = new AntennaGroup[SAMPLING_RESOLUTION][SAMPLING_RESOLUTION];

        int index_limit=1;
        int limit = SAMPLING_RESOLUTION * SAMPLING_RESOLUTION;
        for(int i=0 ; i<SAMPLING_RESOLUTION ; i++){
            for(int j=0 ; j<SAMPLING_RESOLUTION ; j++){
                System.out.println("we zitten nu aan : " + index_limit + "/" + limit);
                index_limit++;


                RadiationPoint rp = radiationPointGrid[i][j];

                double x1 = rp.getXCo();
                double y1 = rp.getYCo();
                
                for(int x=0 ; x<antennas.length ; x++){
                    Antenna a = antennas[x];
                    double x2 = a.getX();
                    double y2 = a.getY();

                    double distanceBetween = MathTools.distanceBetween2Points(x1, y1, x2, y2);

                    try {

                        if(distanceBetween< ca.getRangeRadius(a) && a.getActive() ){
                            AntennaAndDistance aad = new AntennaAndDistance(a, distanceBetween);

                            if(antennaGroupGrid[i][j]==null){
                             
                                AntennaGroup agb = new AntennaGroup();
                                agb.addAntennaAndDistance(aad);
                                antennaGroupGrid[i][j] = agb; //=up-to-date met init-situatie !
                            }
                            else {
                            
                                AntennaGroup agb = antennaGroupGrid[i][j];
                                agb.addAntennaAndDistance(aad);
                                antennaGroupGrid[i][j] = agb; //=up-to-date met init-situatie !
                            }
                        }
                    }
                    catch( InvalidAttributesException e){
                        System.out.println("Error!");
                    }
                }//for
            }//for
        }//for
    }//method


    /**
     * Update the sampled grid at the changed positions.
     *
     * @param Vector<Atenna> v
     */
    public void changeGridElementsForActiveAntenna(Antenna a){
        
            // LET OP !!!  onderstaande berekeningen zijn allemaal voor een XY-assenstelsel
            // zelfs wanneer we naar int-grid-indexen gaan is dit nog steeds voor een XY-assenstelsel
            try {

                //get indexes at the sampled Grid for this antenna :
                Double d1 = new Double( Math.floor( (a.getX() - minX)/step_valueX)); //floor is ok, want index begint van 0: dus index 2.1 is op 0,1,2
                int index_x = d1.intValue();

                Double d2 = new Double( Math.floor( (a.getY() - minY)/step_valueY));
                int index_y = d2.intValue();

                Double range1 = new Double( Math.ceil( ca.getRangeRadius(a) /step_valueX)); //ceil want vanaf we een cel nog maar binnenkomen moeten we ze meetellen
                int range_x = range1.intValue();

                Double range2 = new Double( Math.ceil( ca.getRangeRadius(a) /step_valueY));
                int range_y = range2.intValue();

                // controleer op limieten = we slaan dit op in de velden !
                xMinIndex =  index_x-range_x;
                if(xMinIndex<0)
                    xMinIndex=0;
                xMaxIndex =  index_x+range_x;
                if(xMaxIndex> antennaGroupGrid[0].length-1 )
                    xMaxIndex = antennaGroupGrid[0].length-1;
                yMinIndex =  index_y-range_y;
                if(yMinIndex<0)
                    yMinIndex = 0;
                yMaxIndex =  index_y+range_y;
                if(yMaxIndex> antennaGroupGrid.length-1)
                    yMaxIndex = antennaGroupGrid.length-1;

                //uit of aan maakt geen verschil : als de antenna aanstaat moet er zker gecontroleerd worden
                // staat de antenna uit, dan kan het zijn dat andere sample points niet meer over de limiet gaan !

                for(int y=yMinIndex ; y<=yMaxIndex ; y++){
                    for(int x=xMinIndex ; x<=xMaxIndex ; x++){
                        // De XY-assenstelsel indexen terug mappen op de matrix-index !!
                        antennaGroupGrid[ antennaGroupGrid.length-1 -y][x] = updateOrAddToThisAntennaGroup(antennaGroupGrid[ antennaGroupGrid.length-1 -y][x],
                                                                                                                         a , y ,x,false); //a blijft ALTIJD hetzelfde
                        // x en y gaan we nodig hebben omdat we de index moeten weten van sampledGridWithAntennas.
                    }
                } //for

            }
            catch(InvalidAttributesException e){}

    }//method


    // de indexen zijn dus die van een matrix. We willen het volgens het XY-euclidische assenstelsel.
    public AntennaGroup updateOrAddToThisAntennaGroup(AntennaGroup ag,Antenna a,
                                                       int indexY , int indexX , boolean init) {
        boolean skipLoop = false;
        boolean FOUND =false;

        if(ag==null){//nog leeg, bijv. door initialisatie
            skipLoop = true;
        }


        if(!skipLoop){
            AntennaAndDistance[] aad = ag.getAntennaAndDistance();

            for(int i=0 ; i<aad.length ; i++){
                AntennaAndDistance aadTemp = aad[i];
                Antenna aTemp = aadTemp.getAntenna();

                //UPDATE
                if( a.equals( aTemp)) {
                    double sampledGridRealXco = radiationPointGrid[ radiationPointGrid.length-1 -indexY][indexX].getXCo();
                    double sampledGridRealYco = radiationPointGrid[ radiationPointGrid.length-1 -indexY][indexX].getYCo();

                    aadTemp.setAntenna(a); //we spreken wel over dezelfde antenna, maar instellingen antenna zijn gewijzigd !
                    aadTemp.setDistance( MathTools.distanceBetween2Points(a.getX(), a.getY(), sampledGridRealXco, sampledGridRealYco) );//opslaan:update
         
                    ag.setAntennaAndDistance(i, aadTemp); //terug opslaan in het ag-object !

                    FOUND=true;
                    break;
                }

            }
        }//skip : yes or no ?
        //ADD
        if(!FOUND){
            if(init){
                ag = new AntennaGroup();
            }


            double sampledGridRealXco = radiationPointGrid[ radiationPointGrid.length-1 -indexY][indexX].getXCo();
            double sampledGridRealYco = radiationPointGrid[ radiationPointGrid.length-1 -indexY][indexX].getYCo();

            // dit is de afstand tussen de antenna (die altijd "dezelfde blijft in deze sub-methode") , en de echte xCo en yCo van de cel waar we NU inzitten.
            AntennaAndDistance aadNew = new AntennaAndDistance(a ,  MathTools.distanceBetween2Points(a.getX(), a.getY(), sampledGridRealXco, sampledGridRealYco) );
            //de antenna is nu ook mee opgeslaan.
            ag.addAntennaAndDistance(aadNew);
        }


        return ag;
    }




    public void changeGridElementsForInactiveAntenna(Antenna a){
        try {
            Double d1 = new Double( Math.floor( (a.getX() - minX)/step_valueX)); //floor is ok, want index begint van 0: dus index 2.1 is op 0,1,2
            int index_x = d1.intValue();

            Double d2 = new Double( Math.floor( (a.getY() - minY)/step_valueY));
            int index_y = d2.intValue();

            Double range1 = new Double( Math.ceil( ca.getRangeRadius(a) /step_valueX)); //ceil want vanaf we een cel nog maar binnenkomen moeten we ze meetellen
            int range_x = range1.intValue();

            Double range2 = new Double( Math.ceil( ca.getRangeRadius(a) /step_valueY));
            int range_y = range2.intValue();

            // controleer op limieten = we slaan dit op in de velden !
            xMinIndex =  index_x-range_x;
            if(xMinIndex<0)
                xMinIndex=0;
            xMaxIndex =  index_x+range_x;
            if(xMaxIndex> antennaGroupGrid[0].length-1 )
                xMaxIndex = antennaGroupGrid[0].length-1;
            yMinIndex =  index_y-range_y;
            if(yMinIndex<0)
                yMinIndex = 0;
            yMaxIndex =  index_y+range_y;
            if(yMaxIndex> antennaGroupGrid.length-1)
                yMaxIndex = antennaGroupGrid.length-1;

            for(int y=yMinIndex ; y<=yMaxIndex ; y++){
                for(int x=xMinIndex ; x<=xMaxIndex ; x++){
                    // De XY-assenstelsel indexen terug mappen op de matrix-index !!
                    antennaGroupGrid[ antennaGroupGrid.length-1 -y][x] = deleteFromThisAntennaGroup(antennaGroupGrid[ antennaGroupGrid.length-1 -y][x],
                                                                                                                     a , y ,x); //a blijft ALTIJD hetzelfde
                    // x en y gaan we nodig hebben omdat we de index moeten weten van sampledGridWithAntennas.
                }
            }//for

        }
        catch(InvalidAttributesException e){}
    }


    public AntennaGroup deleteFromThisAntennaGroup(AntennaGroup ag,Antenna a,
                                                  int indexY , int indexX) {
        if(ag==null){//nog leeg, bijv. door initialisatie
            return ag;
        }


        AntennaAndDistance[] aad = ag.getAntennaAndDistance();




        boolean FOUND =false;
        for(int i=0 ; i<aad.length ; i++){
            AntennaAndDistance aadTemp = aad[i];
            Antenna aTemp = aadTemp.getAntenna();

            if (a.equals(aTemp))   {

                ag.removeAntennaAndDistance(i);
                FOUND=true;
                break;
            }
        }

        return ag;

    }
}//class
